package com.ccjk.beusoft.thirdlib.plugin3;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.text.TextUtils;
import android.widget.Toast;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;

import dalvik.system.DexClassLoader;

/**
 * Created by CCJK on 2017/12/2.
 */

public final class PluginManager {
    private static PluginManager instacne = null;
    private Context hostContext;
    private File dexOutDir;
    private HashMap<String, PluginPackage> pluginMap = new HashMap<>(5);

    private PluginManager(Context context) {
        this.hostContext = context;
        dexOutDir = new File(context.getCacheDir(), "pluginDex");
        if (!dexOutDir.isDirectory()) {
            dexOutDir.mkdirs();
        }
    }

    public static PluginManager getInstance(Context context) {
        if (instacne == null) {
            synchronized (PluginManager.class) {
                if (instacne == null) {
                    instacne = new PluginManager(context.getApplicationContext());
                }
            }
        }
        return instacne;
    }

    public void loadApk(String apkPath) {
        PackageInfo packageInfo = hostContext.getPackageManager().getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
        if (packageInfo == null) {
            Toast.makeText(hostContext, "錯誤的apk", Toast.LENGTH_SHORT).show();
            return;
        }
        String pluginPackageName = packageInfo.packageName;
        if (pluginMap.containsKey(pluginPackageName)) return;
        //1. get default activity class name
        String defaultActivityClassName = "";
        if (packageInfo.activities != null && packageInfo.activities.length > 0) {
            defaultActivityClassName = packageInfo.activities[0].name;
        }

        //2. create plugin class loader ******************************
        ClassLoader parentClassLoader = hostContext.getClassLoader();
        DexClassLoader pluginClassLoader = new DexClassLoader(apkPath, dexOutDir.getAbsolutePath(), null, parentClassLoader);

        //3. create plugin assetManager
        AssetManager assetManager = null;
        try {
            assetManager = AssetManager.class.newInstance();
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", new Class[]{String.class});
            addAssetPath.setAccessible(true);
            addAssetPath.invoke(assetManager, apkPath);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //4. create plugin resources
        Resources resources = new Resources(assetManager, hostContext.getResources().getDisplayMetrics(),
                hostContext.getResources().getConfiguration());
        //5.cache plugin package
        pluginMap.put(pluginPackageName,
                new PluginPackage(pluginPackageName, defaultActivityClassName, pluginClassLoader, packageInfo, resources, assetManager)
        );

    }


    public PluginPackage getPluginPackage(String packageName) {
        return pluginMap.get(packageName);
    }

    public void startActivity(Context context, PluginIntent intent) {
        startPluginActivityForResult(context, intent, -1);
    }

    private void startPluginActivityForResult(Context context, PluginIntent intent, int requestCode) {
        PluginPackage pluginPackage = getPluginPackage(intent.pluginPackageName);
        if (pluginPackage == null) {
            Toast.makeText(context, "找不到該插件", Toast.LENGTH_SHORT).show();
            return;
        }
        String pluginActivityName = getActivityName(intent, pluginPackage);
        Class<?> pluginActivityClass = loadPluginClass(pluginPackage.pluginClassLoader, pluginActivityName);
        if (pluginActivityClass == null) {
            Toast.makeText(context, "找不到activity", Toast.LENGTH_SHORT).show();
            return;
        }

//        if (!verifyPluginActivity(pluginActivityClass)) {
//            Toast.makeText(context, "插件Activity沒有繼承BasePluginActivity", Toast.LENGTH_SHORT).show();
//            return;
//        }
        intent.putExtra(Const.KEY_PLUGIN_PACKAGE_NAME, intent.pluginPackageName);
        intent.putExtra(Const.KEY_PLUGIN_ACTIVITY_NAME, pluginActivityName);
        intent.setClass(context, HostProxyActivity.class);
        if (context instanceof Activity) {
            ((Activity) context).startActivityForResult(intent, requestCode);
        } else {
            context.startActivity(intent);
        }
    }

    private boolean verifyPluginActivity(Class<?> clazz) {
        if (BasePluginActivity.class.isAssignableFrom(clazz)) {
            return true;
        }
        return false;
    }

    private Class<?> loadPluginClass(ClassLoader classLoader, String className) {
        try {
            return Class.forName(className, true, classLoader);
        } catch (Exception e) {

        }
        return null;
    }

    private String getActivityName(PluginIntent intent, PluginPackage pluginPackage) {
        String activityName;
        if (TextUtils.isEmpty(intent.pluginComponentName))
            activityName = pluginPackage.defaultActivityClassName;
        else activityName = intent.pluginComponentName;
        if (activityName.startsWith(".")) {
            return intent.pluginPackageName + activityName;
        } else return activityName;

    }
}
